﻿using System.Collections;
using UnityEngine;
using System;
using System.Threading;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
using IMIForUnity;


namespace IMIForUnity
{

	public  partial class BodyMeaMgrImp:MonoBehaviour
	{

		//depthPlayerDataOriginal
		//DEPTHWIDTH * DEPTHHEIGHT;
		int DEPTHWIDTH=640;
		int DEPTHHEIGHT=480;

		/// <summary>
		/// 所有玩家体感数据存储数组.
		/// </summary>

		ImiPlayerInfo prevPlayer=null;    //we create the prevPlayer, because sometimes there may be more than 1 player in side measurement area.
		                                  //It will be better we fix on a certain guy.
		 
		/// <summary>
		/// 包含玩家信息的深度数据,原始数据，直接从设备返回的
		/// </summary>
		private ushort[] depthPlayerDataOriginal;

		public ushort[] DepthPlayerDataOriginal {
			get {
				return depthPlayerDataOriginal;
			}
			set {
				depthPlayerDataOriginal = value;
			}
		}


		public ushort[] depthUserDataBack;

		/// <summary>
		/// 所有玩家彩色数据.
		/// </summary>
		private byte[] allUsersDepthData;

		public byte[] AllUsersDepthData {
			get {
				return allUsersDepthData;
			}
			set {
				allUsersDepthData = value;
			}
		}

		//when we find a point on the boundary on a contour, such as body contour, we compare one pixel and the pixel next to it.
		//if both pixel are inside the body contour, we assume that the depth difference betweent them is smaller than  boundThreshval.
		//if not, we take the first spot as the one one the boundary of the contour.
		public  ushort boundThreshval = 380;   //unit mm  0.38m

		//Set the tilting down angle. it is in the range from14 to 
		float setDeviceHeight = 1700;  // In Default, we put the imi device on the height of 170 cm.
		float tiltDownAngle = 17;
		float HeightDiff = 0f;
		float halfvfov = 24f;

		//just for showing pixel poses.
		int headOrigPixPos = 0;
		int headTopPixPosY = 0;
		int headOrigDepth = 0;
		int headTopDepth = 0;
		public Dictionary<uint, float> PlayHeightDic;
		public FloatSmoothTool heightSmoothTool=new FloatSmoothTool();
		ArrayList heightSmoothArr=new ArrayList();

		private  float playerHeight = 0f;


		public float PlayerHeight {
			get {
				return playerHeight;
			}
		}
		public  float playerHeight2 = 0f;
		public float heightOffsetY=50;


		public bool isPlayerDetected;
		public bool isPlayerInsideArea;
		public bool isPlayerInsdieArewWithSkeletonTracked;
		public bool isPlayerFrontToDevice;

		//We make ranks for "Side Condition".
		//if the abs(headShoulderDeltaZXRatio) is bigger than 2 we set it as side
		//is smaller than 2 but bigger than 1 we set the sidestate value to 6 or 7
		//6 is a bit too left. 7 is a bit too right.
		public bool isPlayerSideToDevice;
		public bool isPlayerSideToDeviceALittleLeft=false;
		public bool isPlayerSideToDeviceALittleRight=false;

		//do we draw 
		public bool isShowMeaDataOnColorMap=false;


		public bool isDuringFrontProcess;
		public bool isDuringSideProcess;


		//pix pos for some parts of the body
		int hipsPixPosX = 0;
		int hipsPixPosY = 0;
		int hipsPixPosZ = 0;

		//pix pos for some parts of the body
		int chestPixPosX = 0;
		int chestPixPosY = 0;
		int chestPixPosZ = 0;

		//The following is for the range in Z direction during which the player can be detected.
		float farZLimit=2.7f;
		float nearZLImit=1.3f;
		float xLimit=0.35f;


		public  bool enableFrontProcess=false;
		public  bool enableSideProcess=false;


		int adjustDeepingLengthForSideWaist=80;  
		int adjustDeepingLengthForSideChest=80;  
		int adjustDeepingLengthForSideHips=100;  

		FloatSmoothTool XZDeltaSmth;

		public  float ArmLength=0f;
		public  float LegLength=0f;
		public  float ShoulderWidth=0f;
//		FloatSmoothTool ArmLengthSmth;
//		FloatSmoothTool LegLengthSmth;
//		FloatSmoothTool ShoulderWidthSmth;

		ArrayList ArmLengthArr=new ArrayList();
		ArrayList LegLengthArr=new ArrayList();
		ArrayList ShoulderWidthArr=new ArrayList();

		float headShoulderDeltaZXRatio=0f;
		public float HeadShoulderDeltaXZRatio {
			get {
				return headShoulderDeltaZXRatio;
			}
		}

		Tick PlayerSideRecheckTimer;

		//If we found a player inside the center area but with no skeleton, we need to track his skeleton and start this timer.
		Tick TrackPlayerSkeletonTimer;
		int trackerSkeletonTimeSum=4000;
		//when we in the period of tracking the skeleton of a player, we set duringTrackSkeletonFlag = true. After trackerSkeletonTimeSum   is passed or skeleton is tracked , we set it false.
		public  bool duringTrackSkeletonFlag=false;
		public  int CurrtrackingSkeletonID=0;

		//since 2017 03 17, this flag is for enable us to measure side thickness or not.
		//In the beginning of side measurement, which is in BeginMeasureSide(), we will set this flag to false.
		//And then we will detect the orientation of the measured player.  
		//If the guy does not side facing the dev enough,  we will disp a clock to show his orien and tell him to pose more side
		//Rightly after the 1st sec the player side face the dev, we will set the flag to true and trigger the side measure
		//Since then till end, we will not judge the flag anymore, no matter in reality the guy side face the dev or not.
		public bool enableMeaSide=false;


		//Since 2017 06 01  for new way to detect the front depth of body.
		public FrontMeaMgr chestFrontDepthLineMgr;
		public FrontMeaMgr waistFrontDepthLineMgr;
		public FrontMeaMgr hipsFrontDepthLineMgr;


		//public BodyMeaMgrImp( byte[] tallUsersDepthData)
		void Start()
		{
			DEPTHWIDTH=640;
			DEPTHHEIGHT=480;
			//if(ImiManager.GetInstance().depthResolution!=ImiWrapper.ImiDepthResolution.IMI_DEPTH_RESOLUTION_640x480)
			if(ImiManager.GetInstance().depthResolution!=ImiResolution.Type._640x480)
			{
				Debug.LogError("The bodymea resolution is set fixed to 640 480. Please Change depthResolution of IMIManager to 640 480"  );

			}


			depthUserDataBack=new ushort[DEPTHWIDTH*DEPTHHEIGHT];

			//depthPlayerDataOriginal=tdepthPlayerDataOriginal;
			//allUsersDepthData=tallUsersDepthData;

			XZDeltaSmth=new FloatSmoothTool(5);
			
			isPlayerDetected=false;
			isPlayerInsideArea=false;
			isPlayerInsdieArewWithSkeletonTracked=false;
			isPlayerFrontToDevice=false;
			isPlayerSideToDevice=false;
			isPlayerSideToDeviceALittleLeft = false;
			isPlayerSideToDeviceALittleRight = false;

			isDuringFrontProcess=false;
			isDuringSideProcess=false;

			heightOffsetY=PlayerPrefs.GetFloat("heightOffsetY",50f);

			PlayerSideRecheckTimer = new Tick (0,1000);
			PlayerSideRecheckTimer.setCallBack (SwitchOffisDuringSideProcess);
			enableMeaSide=false;
			//PlayerSideRecheckTimer.reStart


			//Since 2017 0413 setPlayerControlMode as custom;

			duringTrackSkeletonFlag=false;
			TrackPlayerSkeletonTimer=new Tick(0,trackerSkeletonTimeSum);
			TrackPlayerSkeletonTimer.setCallBack(trackingSkeletonTimerOver);
			TrackPlayerSkeletonTimer.stop();



		}



		public void SetPlayerInfoAndUserDepthData( byte[] tallUsersDepthData)
		{
			if(ImiManager.GetInstance().depthResolution!=ImiResolution.Type._640x480)
			{
				Debug.LogError("The bodymea resolution is set fixed to 640 480. Please Change depthResolution of IMIManager to 640 480"  );
				
			}

			allUsersDepthData=tallUsersDepthData;
		}







		public void SetPlayerSideRecheckTimer(bool flag)
		{
			if (flag) {
				PlayerSideRecheckTimer.reStart ();
			
			} else {
			
				PlayerSideRecheckTimer.stop ();
			}

		}



		void AddColorToDepthTex ()
		{
			int w = DEPTHWIDTH;
			int h = DEPTHHEIGHT;

			for (int i=0; i<100; i++) {
				for (int j=0; j<100; j++) {
					allUsersDepthData [(j * w + i) * 4] = (byte)(255);
					allUsersDepthData [(j * w + i) * 4 + 1] = (byte)(0);
					allUsersDepthData [(j * w + i) * 4 + 2] = (byte)(0);
					allUsersDepthData [(j * w + i) * 4 + 3] = 10;
				}
			}
		}



		bool tmpPlayerInside=false;   //Found a guy in central area, but not sure his skeleton tracked or not.
		bool tmpPlayerInsideWithGoodSkeleton=false;   //determin if this guy  is  skeleton well  or  not.  Only the guy inside area 
		                                              //and with good skeleton can be measured.  If not, we give certain signal.

		bool tmpDuringFrontProcess=false;

		bool tmpIsPlayerFront = false;

		bool tmpIsPlayerSide = false;
		bool tmpIsPlayerSideALittleLeft = false;
		bool tmpIsPlayerSideALittleRight = false;

		bool tmpDoWeFoundPlayerLastTime=false;
		bool tmpDoWeGetANewPlayerThisTime=false;

		public int  currInsidePlayerID;  //store the player id who is inside measurement area.
		public int  currPlayerCountInsideMiddleArea=0;   //get the numbers of players inside middle area. If more than 1, we need to return a signal
		public int currInsidePlayerPixID=-1;  //The center player id got by detecting a pixel line in the low middle position.


		public  void BodyMea(ushort[] depthData,  Dictionary<int, ImiPlayerInfo> playerInfos )
		{ 
			if ((depthData != null) && (AllUsersDepthData != null)) {

				depthPlayerDataOriginal = depthData;
				tmpPlayerInside = false;
				tmpPlayerInsideWithGoodSkeleton=false;
				tmpDuringFrontProcess = false;
				tmpIsPlayerSide = false;
				tmpIsPlayerSideALittleLeft = false;
				tmpIsPlayerSideALittleRight = false;
				tmpIsPlayerFront = false;
				tmpDoWeFoundPlayerLastTime = false;
				tmpDoWeGetANewPlayerThisTime = false;

				if (playerInfos.Count > 0) {

					isPlayerDetected = true;
				    
					currPlayerCountInsideMiddleArea=GetPlayerCountInsideMiddleArea(playerInfos,xLimit,nearZLImit,farZLimit);

					if(currPlayerCountInsideMiddleArea>0)
					{

						#region for measure the player if we found him before.
					    if (prevPlayer != null) {

						//this loop is for finding the guy we measured last frame. If we found him , we measure him in this loop 
						//and end this frame directly  set tmpDoWeFoundPlayerLastTime true. 
						//If not , we set tmpDoWeFoundPlayerLastTime false and detect a new guy.
						foreach (KeyValuePair<int, ImiPlayerInfo> pair in playerInfos) {		
					
					
							if (      
							    (pair.Value.GetUserId()==prevPlayer.GetUserId())
							   && 
							    (Mathf.Abs (pair.Value.GetPlayerPosition ().x) < xLimit)
							   && (Mathf.Abs (pair.Value.GetPlayerPosition ().z) > nearZLImit)
							       && (Mathf.Abs (pair.Value.GetPlayerPosition ().z) < farZLimit)   //Change the range from 1.5-2.3  to  1-2.6.
							 	   && (JudgeCenterPixleLineContainsPlayerPixel (true))) { //in meters
								//Debug.Log ("Position-------------------------   " +pair.Value.GetPlayerPosition().x.ToString() );

								tmpPlayerInside=true;
								tmpDoWeFoundPlayerLastTime=true;	
								//pair.Value.trackingState==ImiSkeletonTrackingState.IMI_SKELETON_TRACKED;
								prevPlayer=pair.Value;

								currInsidePlayerID=prevPlayer.GetUserId();
								if( pair.Value.trackingState==ImiSkeletonTrackingState.IMI_SKELETON_TRACKED)   //one guy shows before and he is inside area and with good  skeleton.
								{
									trackingSkeletonTimerOver();
									MeasureCertainPlayer (ref  playerInfos, prevPlayer.GetUserId());
													
									break;
								}
								else
								{
									if((CurrtrackingSkeletonID==prevPlayer.GetUserId())&&(duringTrackSkeletonFlag))
									{
										//If the id is the tracking skeletonID, we do not need to do anything more, just let it keeps tracking.

										break;
									}
									else
									{
										StartTrackingSkeleton(playerInfos, prevPlayer.GetUserId() );
										break;
									}

								   								
								}

							}
						}	
					}

						#endregion

                        # region if not find the prev guy, we get the guy inside area and closet to the device and measure him
								if(!tmpDoWeFoundPlayerLastTime)
								{
						           trackingSkeletonTimerOver();
						            


									foreach (KeyValuePair<int, ImiPlayerInfo> pair in playerInfos) {	

							         if ( (Mathf.Abs (pair.Value.GetPlayerPosition ().x) <xLimit)
										    && (Mathf.Abs (pair.Value.GetPlayerPosition ().z) > nearZLImit)
										    && (Mathf.Abs (pair.Value.GetPlayerPosition ().z) < farZLimit)
										
								    && (JudgeCenterPixleLineContainsPlayerPixel (true))) { //in meters

							             	tmpPlayerInside=true;

							             	currInsidePlayerID=pair.Value.GetUserId();
											if(!tmpDoWeGetANewPlayerThisTime)
											{
											    prevPlayer=pair.Value;
												tmpDoWeGetANewPlayerThisTime=true;
											}
											else
											{
												if(Mathf.Abs (pair.Value.GetPlayerPosition ().z)< 
													Mathf.Abs (prevPlayer.GetPlayerPosition ().z)   )
												{
													prevPlayer=pair.Value;
												}
											}
										}
									}	


						            //if we found a qualified guy this time.
						 
									if (tmpDoWeGetANewPlayerThisTime) {

										if( prevPlayer.trackingState==ImiSkeletonTrackingState.IMI_SKELETON_TRACKED)
										{
								//We do not need to set  	tmpPlayerInsideWithGoodSkeleton=true;  for we already wrote this code in   MeasureCertainPlayer;     
											MeasureCertainPlayer (ref  playerInfos, prevPlayer.GetUserId ());
										}
							            else
										{
						                 	tmpPlayerInsideWithGoodSkeleton=false;
						                  	//ImiManager.GetInstance().SetTrackingUserId( prevPlayer.GetUserId());
								            StartTrackingSkeleton( playerInfos,  prevPlayer.GetUserId() );
										}
									}
								}
						#endregion
					}


				} else {
					isPlayerDetected = false;
					trackingSkeletonTimerOver();
				}		


				if(!tmpPlayerInside)
				{
					trackingSkeletonTimerOver();
					currInsidePlayerID=-10;
				}



				isPlayerInsideArea = tmpPlayerInside;	
				isPlayerInsdieArewWithSkeletonTracked=tmpPlayerInsideWithGoodSkeleton;
				isDuringFrontProcess = tmpDuringFrontProcess;
				isPlayerSideToDevice = tmpIsPlayerSide;
				isPlayerSideToDeviceALittleLeft = tmpIsPlayerSideALittleLeft;
				isPlayerSideToDeviceALittleRight = tmpIsPlayerSideALittleRight;
				isPlayerFrontToDevice = tmpIsPlayerFront;
		//		ImiBodyMeaMgr.Instance.textureReady = true;

			}
		}



		public int GetPlayerCountInsideMiddleArea(Dictionary<int, ImiPlayerInfo> playerInfos, float xLimit, float zNear, float zFar)
		{

			int playerCount=0;
			foreach (KeyValuePair<int, ImiPlayerInfo> pair in playerInfos) {			
				
				if (      
				     (Mathf.Abs (pair.Value.GetPlayerPosition ().x) <  Mathf.Abs(xLimit))
				    && (Mathf.Abs (pair.Value.GetPlayerPosition ().z) > nearZLImit)
				    && (Mathf.Abs (pair.Value.GetPlayerPosition ().z) < farZLimit)   //Change the range from 1.5-2.3  to  1-2.6.
				   ) 
				{ 
					playerCount++;
				}
//				else
//				{
//					ImiManager.GetInstance().SetUnTrackingUserId(pair.Value.GetUserId());
//				}
			}
			return playerCount;

		}




		public void MeasureCertainPlayer(ref Dictionary<int, ImiPlayerInfo> playerInfos , int UserID  )
		{
			tmpPlayerInside=true;
			tmpPlayerInsideWithGoodSkeleton=true;

			headShoulderDeltaZXRatio=GetheadShoulderDeltaZXRatio(playerInfos,  UserID );
			if(headShoulderDeltaZXRatio<0.4f)
			{
				tmpIsPlayerFront=true;
			}
			else
			{
				tmpIsPlayerFront=false;
			}

			if( Mathf.Abs(headShoulderDeltaZXRatio)>2f)
			{
				tmpIsPlayerSide=true;
			}
			else
			{
				tmpIsPlayerSide=false;
				if((headShoulderDeltaZXRatio < -1) && (headShoulderDeltaZXRatio > -2f)) {
					tmpIsPlayerSideALittleLeft = true;							    
				}

				if((headShoulderDeltaZXRatio> 1) && (headShoulderDeltaZXRatio <2f)) {
					tmpIsPlayerSideALittleRight = true;							    
				}
			}										




			if (enableFrontProcess) {
				if(tmpIsPlayerFront)
				{
					tmpDuringFrontProcess=true;


					ProcessFront (ref playerInfos,UserID, isShowMeaDataOnColorMap);

				}
			}




		



			//bool tmpDruingSidePorcess=false;
			if(enableSideProcess)
			{

				if(tmpIsPlayerSide)
				{
					enableMeaSide=true;
				}

				//Since 2017 03 17.
				//we only need one frame of  tmpIsPlayerSide==true to enable  enableMeaSide.
				//After it we trigger ProcessSide()  no matter  the player side face dev or not.
				if(enableMeaSide)
				{
				    //Since  2017 03 17   we trigger side measure directly after 
				    //enableSideProcess is set to true.    NO matter the player is side face the dev or not.

					ProcessSide( ref playerInfos ,UserID, isShowMeaDataOnColorMap );

				}

			}
	
		}


		void StartTrackingSkeleton(Dictionary<int, ImiPlayerInfo> playerInfos,  int currID)
		{
			ImiManager.GetInstance().SetTrackingUserId(currID);
			//ImiManager.GetInstance()

			CurrtrackingSkeletonID=currID;
			duringTrackSkeletonFlag=true;
			TrackPlayerSkeletonTimer.reStart();


			foreach (KeyValuePair<int, ImiPlayerInfo> pair in playerInfos) {			
				if ( pair.Value.GetUserId()!=   currID ) 
				{ 
					ImiManager.GetInstance().SetUnTrackingUserId(pair.Value.GetUserId());
				}
			}
		}




		void trackingSkeletonTimerOver()
		{
			TrackPlayerSkeletonTimer.stop();
			duringTrackSkeletonFlag=false;
			CurrtrackingSkeletonID=-100;
		}




		public int GetDepthValOfCertainPixPos(int x,int y, bool isDraw)
		{
			if(depthPlayerDataOriginal!=null)
			{
			if (x < 0)
				x = 0;
			if (x > DEPTHWIDTH - 1)
				x = DEPTHWIDTH - 1;
			if (y < 0)
				y = 0;
			if (y > DEPTHHEIGHT - 1)
				y = DEPTHHEIGHT - 1;

			int depthVal = ((depthPlayerDataOriginal [y * DEPTHWIDTH + x]) >> 3);

			if (isDraw) {
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray (
					DEPTHWIDTH, DEPTHHEIGHT, x, y,5, allUsersDepthData, 0, 255, 255, 255);			
			}

			return depthVal;
			}
			return 0;
		
		}





		public void SwitchOffisDuringSideProcess()
		{
			Debug.Log ("aaaaaaaaaaa");
			//PlayerSideRecheckTimer.reStart ();
			isDuringSideProcess = false;
		}




	

		//return if one center line of several pixels contains any pixel including the player index 
		//If it contains, we store the player id.
		public bool JudgeCenterPixleLineContainsPlayerPixel(bool isDraw)
		{
			if (depthPlayerDataOriginal != null) {

				int centerPixX = 0;
				int centerPixY = 0;


				if (DEPTHWIDTH > 0) {
					centerPixX = DEPTHWIDTH / 2;
				} else {
					DEPTHWIDTH = 640;
					centerPixX = 320;
				}


				//	depthPlayerDataOriginal  [chestupy *dw +chestupx] & 7



				if (DEPTHHEIGHT > 0) {
					centerPixY = (DEPTHHEIGHT / 3)*2;
				} else {	
					DEPTHHEIGHT = 480;
					 centerPixY = 320;
				}

				if (isDraw) {
					DrawHorilineOnUserDepthColor (allUsersDepthData, DEPTHWIDTH, DEPTHHEIGHT, 
						(int)centerPixX - 40, (int)centerPixX + 40, (int)centerPixY, 255, 255, 0, 255);
				}


				for (int i = centerPixX - 40; i < centerPixX + 40; i++) {
			
					if ((depthPlayerDataOriginal [centerPixY * DEPTHWIDTH + i] & 7) > 0) {

						currInsidePlayerPixID= (depthPlayerDataOriginal [centerPixY * DEPTHWIDTH + i] & 7);
						return true;
					}
				}

				currInsidePlayerPixID=-1;
				return false;
			}
		
			return false;
		}


	
		Vector3 headTopPixPos=Vector3.zero;

		void ProcessFront(ref Dictionary<int, ImiPlayerInfo> playerInfos , int userID, bool isDrawOnDepthMap  )
		{
			try{
			//Since  2017 06 01  make a contour frame for the center player.
				headTopPixPos=GetHeadTopPixPos(ref playerInfos, userID, false);
				  
				int leftKneeX=0;
				int leftKneeY=0;
				int leftKneeZ=0;
				GetPlayerJointPixPos( ref playerInfos, userID , ref leftKneeX,
				                              ref leftKneeY,
				                              ref leftKneeZ,ImiSkeleton.Index.KNEE_LEFT,false);
            
				FrameCenterPlayer(userID, headTopPixPos,leftKneeY,false);
				ProcessChest2(ref playerInfos,	 userID, isDrawOnDepthMap);
				ProcessWaist2(	ref playerInfos, userID, isDrawOnDepthMap);
				ProcessHips2(ref playerInfos,	 userID, isDrawOnDepthMap);

			

			

			//Before 2017 06 01 old way to measure body.
				GetHeightForPlayer (ref  playerInfos , userID, isDrawOnDepthMap );
			//ProcessChest (userID, isDrawOnDepthMap);

			//ProcessWaistFront (userID, isDrawOnDepthMap);

			//ProcessHipsFront (userID, isDrawOnDepthMap);
				GetShoulderWidth(ref playerInfos,userID,false);
				GetArmLength(ref playerInfos,userID);
				GetLegLength(ref playerInfos,userID);


			if(isDrawOnDepthMap)
			{
					DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.HIP_LEFT
			                          ,7,0,255,120,255);
//
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.KNEE_LEFT
//			                          ,7,255,0,0,255);
//
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.ELBOW_LEFT
//			                          ,7,255,0,0,255);
//			
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.ELBOW_RIGHT
//			                          ,7,255,0,0,255);	 
//
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.WRIST_LEFT
//					                          ,7,255,255,255,255);

//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.WRIST_RIGHT
//					                          ,7,255,255,255,255);
//
//
					DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.HIP_RIGHT
					                          ,7,0,255,120,255);
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.FOOT_LEFT
//					                          ,7,255,255,255,255);

					DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.HIP_CENTER
			                          ,9,100,255,0,255);
					DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.SPINE
			                          ,7,255,100,0,255);
					DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.SHOULDER_CENTER
			                          ,5,0,255,255,255);

					//Draw hori line on chest waist hips middle part.
//					for(int i=LeftChestLimit;i<RightChestLimit;i++)
//					{
//						DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray(DEPTHWIDTH,DEPTHHEIGHT,
//						                                                  i,chestdownY,
//						                                                  5,allUsersDepthData,0,255,255,255);
//					}	
//					
//					
//					for(int i=LeftWaistLimit;i<RightWaistLimit;i++)
//					{
//						DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray(DEPTHWIDTH,DEPTHHEIGHT,
//						                                                  i,WaistY,
//						                                                  5,allUsersDepthData,0,255,255,255);
//					}		
//					//				
//					for(int i=LeftHipsLimit;i<RightHipsLimit;i++)
//					{
//						DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray(DEPTHWIDTH,DEPTHHEIGHT,
//						                                                  i,HipsY,
//						                                                  5,allUsersDepthData,0,255,255,255);
//					}		

		

				}

			}
			catch(Exception e)
			{
				Debug.LogError("Error in Process Front: "+ e.ToString() );

			}

		}


		void ProcessSide(ref Dictionary<int, ImiPlayerInfo> playerInfos , int userID, bool isDrawOnDepthMap  )
		{
			ProcessWaistSide( ref playerInfos,   userID, isDrawOnDepthMap);
			ProcessChestSide( ref playerInfos,  userID, isDrawOnDepthMap);
			ProcessHipsSide( ref playerInfos,   userID, isDrawOnDepthMap);
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.HIP_LEFT
//			                          ,7,255,0,0,255);
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.KNEE_LEFT
//			                          ,7,255,0,0,255);
//			
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.HIP_RIGHT
//			                          ,7,255,0,0,255);
//			DrawJointsMarksOnDepthMap(userID, ImiSkeleton.Index.FOOT_LEFT
//			                          ,7,255,0,0,255);
//			

			if(isDrawOnDepthMap)
			{
				DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.HIP_CENTER
					                          ,11,255,255,255,255);
				DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.SPINE
					                          ,11,255,255,255,255);
				DrawJointsMarksOnDepthMap(ref playerInfos,userID, ImiSkeleton.Index.SHOULDER_CENTER
					                          ,11,255,255,255,255);

			}
		}


		public float shoulderWTmp=0f;
		void GetShoulderWidth(ref Dictionary<int, ImiPlayerInfo> playerInfos, int userID, bool isDrawOrNot )
		{
			ImiWrapper.ImiVector4 lShoulderjointPosV4 =
				playerInfos [userID].skeletons[(int)ImiSkeleton.Index.SHOULDER_LEFT].positionV4;
					

			ImiWrapper.ImiVector4 rShoulderjointPosV4 =
				playerInfos [userID].
					skeletons[(int)ImiSkeleton.Index.SHOULDER_RIGHT].positionV4;


//before  1125 using shouder sys positons directly
//			Vector3 lshVec=new Vector3(lShoulderjointPosV4.x,lShoulderjointPosV4.y,lShoulderjointPosV4.z);
//			Vector3 rshVec=new Vector3(rShoulderjointPosV4.x,rShoulderjointPosV4.y,rShoulderjointPosV4.z);
//			
//			float shoulderWTmp=IMIBodyMeaTool.GetShoulderWidth(lshVec, rshVec);
////			ShoulderWidthSmth.InsertValue(shoulderWTmp);//
////			ShoulderWidth=ShoulderWidthSmth.GetFilteredValue();
//			ShoulderWidthArr.Add(shoulderWTmp);


			int lx=0;
			int ly=0;
			int lz=0;
			
			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				lShoulderjointPosV4,
				ref lx,
				ref ly,
				ref lz,
				ImiResolution.Type._640x480);


			lx=RangeValue(lx,0,DEPTHWIDTH);
			ly=RangeValue(ly,0,DEPTHHEIGHT);
			int shoulderDepth=depthPlayerDataOriginal[ ly*DEPTHWIDTH+lx]>>3;

			shoulderWTmp=GetThicknessFromOnePixPos(depthPlayerDataOriginal,
			                                             DEPTHWIDTH, 
			                                             DEPTHHEIGHT, 
			                                             lx,
			                                             ly,
			                                             boundThreshval,			               
			                                             shoulderDepth, 
			                                             isDrawOrNot);	
			ShoulderWidthArr.Add(shoulderWTmp);
		}


		void GetArmLength(ref Dictionary<int, ImiPlayerInfo> playerInfos, int userID )
		{
			ImiWrapper.ImiVector4 lShoulderjointPosV4 =
				playerInfos [userID].
					skeletons[(int)ImiSkeleton.Index.SHOULDER_LEFT].positionV4;
			
			ImiWrapper.ImiVector4 rShoulderjointPosV4 =
				playerInfos [userID].
					skeletons[(int)ImiSkeleton.Index.SHOULDER_RIGHT].positionV4;

			ImiWrapper.ImiVector4 lWristjointPosV4 =
				playerInfos [userID].
					skeletons[(int)ImiSkeleton.Index.WRIST_LEFT].positionV4;
			
			ImiWrapper.ImiVector4 rWristjointPosV4 =
				playerInfos [userID].
					skeletons[(int)ImiSkeleton.Index.WRIST_RIGHT].positionV4;

			


			Vector3 lshVec=new Vector3(lShoulderjointPosV4.x,lShoulderjointPosV4.y,lShoulderjointPosV4.z);
			Vector3 rshVec=new Vector3(rShoulderjointPosV4.x,rShoulderjointPosV4.y,rShoulderjointPosV4.z);
			Vector3 lWristVec=new Vector3(lWristjointPosV4.x,lWristjointPosV4.y,lWristjointPosV4.z);
			Vector3 rWristVec=new Vector3(rWristjointPosV4.x,rWristjointPosV4.y,rWristjointPosV4.z);


			float armlengthTmp=IMIBodyMeaTool.GetArmLength(lshVec, rshVec,lWristVec,rWristVec);
//			ArmLengthSmth.InsertValue(armlengthTmp);
//			
//			ArmLength=ArmLengthSmth.GetFilteredValue();

			ArmLengthArr.Add(armlengthTmp);
			
		}


		void GetLegLength( ref Dictionary<int, ImiPlayerInfo> playerInfos, int userID )
		{
//			ImiWrapper.ImiVector4 lhipPosV4 =
//				playerInfos [userID].
//					jointsPosV4[(int)ImiSkeleton.Index.HIP_LEFT];
//			
//			ImiWrapper.ImiVector4 rhipPosV4 =
//				playerInfos [userID].
//					jointsPosV4[(int)ImiSkeleton.Index.HIP_RIGHT];
//			
//			ImiWrapper.ImiVector4 lfootPosV4 =
//				playerInfos [userID].
//					jointsPosV4[(int)ImiSkeleton.Index.FOOT_LEFT];
//			
//			ImiWrapper.ImiVector4 rfootPosV4 =
//				playerInfos [userID].
//					jointsPosV4[(int)ImiSkeleton.Index.FOOT_RIGHT];			
//			
//			
//			Vector3 lhipVec=new Vector3(lhipPosV4.x,lhipPosV4.y,lhipPosV4.z);
//			Vector3 rhipVec=new Vector3(rhipPosV4.x,rhipPosV4.y,rhipPosV4.z);
//			Vector3 lfootVec=new Vector3(lfootPosV4.x,lfootPosV4.y,lfootPosV4.z);
//			Vector3 rfootVec=new Vector3(rfootPosV4.x,rfootPosV4.y,rfootPosV4.z);
//			
//			
//			float leglengthtmp=IMIBodyMeaTool.GetLegLength(lhipVec, rhipVec,lfootVec,rfootVec);

//			LegLengthSmth.InsertValue(leglengthtmp);
//			LegLength=LegLengthSmth.GetFilteredValue();

			ImiWrapper.ImiVector4 hipLeftPos =
								playerInfos [userID].
									skeletons[(int)ImiSkeleton.Index.HIP_LEFT].positionV4;
				
			int lx=0;
			int ly=0;
			int lz=0;

			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				hipLeftPos,
				ref lx,
				ref ly,
				ref lz,
				ImiResolution.Type._640x480);


			ImiWrapper.ImiVector4 hipRightPos =
				playerInfos [userID].
					skeletons[(int)ImiSkeleton.Index.HIP_RIGHT].positionV4;
			
			int rx=0;
			int ry=0;
			int rz=0;
			
			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				hipRightPos,
				ref rx,
				ref ry,
				ref rz,
				ImiResolution.Type._640x480);




			
			float leglengthtmpleft = IMIBodyMeaTool.GetHeightByHeadTopPixPos (480, 640, tiltDownAngle, 48, ly, lz, setDeviceHeight,0f);
			float leglengthtmpright = IMIBodyMeaTool.GetHeightByHeadTopPixPos (480, 640, tiltDownAngle, 48, ry, rz, setDeviceHeight,0f);
			
			LegLengthArr.Add( Mathf.Abs(leglengthtmpleft+leglengthtmpright)/2*1.08f);

		}


		  






		public void  ClearPrevData()
		{
//			chestSmthWideness.ClearAll();
//			chestSmthThickness.ClearAll();
//
//			waistSmthWideness.ClearAll();
//			waistSmthThickness.ClearAll();
//
//
//			hipsSmthWideness.ClearAll();
//			hipsSmthThickness.ClearAll();

		    heightSmoothTool.ClearAll();
//			ArmLengthSmth.ClearAll();
//			LegLengthSmth.ClearAll();
//			ShoulderWidthSmth.ClearAll();

			XZDeltaSmth.ClearAll();
          
			chestSmthWidthArr.Clear();
			chestSmthThicknessArr.Clear();
			waistSmthThickArr.Clear();
			waistSmthWidthArr.Clear();
			hipsSmthWidthArr.Clear();
			hipsSmthThicknessArr.Clear();

			heightSmoothArr.Clear();
			ArmLengthArr.Clear();
			LegLengthArr.Clear();
			ShoulderWidthArr.Clear();
			isDuringSideProcess = false;
		    enableFrontProcess=false;
		    enableSideProcess=false;

			chestFrontDepthLineMgr.ClearSampleDatas ();
			chestFrontDepthLineMgr.ClearAllBody1DDataArr ();

			waistFrontDepthLineMgr.ClearSampleDatas ();
			waistFrontDepthLineMgr.ClearAllBody1DDataArr ();

			hipsFrontDepthLineMgr.ClearSampleDatas ();
			hipsFrontDepthLineMgr.ClearAllBody1DDataArr ();
		}
	




		public void GetHeightForPlayer (  ref Dictionary<int, ImiPlayerInfo> playerInfos ,int userID, bool isDrawOnDepthMap )
		{
			float currHeight = GetHeight(ref playerInfos ,userID, isDrawOnDepthMap );
			heightSmoothTool.InsertValue (currHeight);
			playerHeight2 = heightSmoothTool.GetFilteredValue ();

			heightSmoothArr.Add(currHeight);
		}

	
		public void GetPlayerJointPixPos (  ref Dictionary<int, ImiPlayerInfo> playerInfos, 
			int userID, ref int PosX, ref int PosY, ref int PosZ, 
			ImiSkeleton.Index jointIDX, bool isDrawOnDepthMap)
		{
			int w = DEPTHWIDTH;
			int h = DEPTHHEIGHT;



			ImiWrapper.ImiVector4 jointPosV4 =
				playerInfos [userID].
					skeletons[(int)jointIDX].positionV4;

			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				jointPosV4,
				ref PosX,
				ref PosY,
				ref PosZ,
				ImiResolution.Type._640x480);


			if(PosX<0)PosX=0;
			if(PosY<0)PosY=0;
			if(PosX>=w)PosX=w-1;
			if(PosY>=h)PosY=h-1;

			if (isDrawOnDepthMap)
			if (isSpotInsideDepthMap (hipsPixPosX, hipsPixPosY)) {
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray (w, h, hipsPixPosX, hipsPixPosY, 7, allUsersDepthData, 0, 255, 0, 255);		
			}
		}

		private Vector3 DrawJointsMarksOnDepthMap (ref Dictionary<int, ImiPlayerInfo> playerInfos, 
			int controlId, ImiSkeleton.Index  skeletonPosIdx, int pixelWidth, byte r, byte g, byte b, byte a)
		{
			int depthX = 0;
			int depthY = 0;
			int depthZ = 0;

			int w = DEPTHWIDTH;
			int h = DEPTHHEIGHT;



			ImiWrapper.ImiVector4 jointPosV4 =
				playerInfos [controlId].
					skeletons[(int)skeletonPosIdx].positionV4;

			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				jointPosV4,
				ref depthX,
				ref depthY,
				ref depthZ,
				ImiResolution.Type._640x480);



			if (isSpotInsideDepthMap (depthX, depthY)) {
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray (w, h, depthX, depthY, pixelWidth, allUsersDepthData, r, g, b, 255);		
			}	


			return new Vector3(depthX,depthY,depthZ   );
		}



		private Vector3 DrawJointsMarksOnDepthMap (Vector3 worldspace, 
		                                           int pixelWidth, byte r, byte g, byte b, byte a)
		{
			int depthX = 0;
			int depthY = 0;
			int depthZ = 0;
			
			int depthMapw = DEPTHWIDTH;
			int depthMaph = DEPTHHEIGHT;
			
			
			
			ImiWrapper.ImiVector4 jointPosV4 =
			new ImiWrapper.ImiVector4();

			jointPosV4.x=worldspace.x;
			jointPosV4.y=worldspace.y;
			jointPosV4.z=worldspace.z;
			jointPosV4.w=1;
			
			


			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				jointPosV4,
				ref depthX,
				ref depthY,
				ref depthZ,
				ImiResolution.Type._640x480);			
			
			
			if (isSpotInsideDepthMap (depthX, depthY)) {
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray (depthMapw, depthMaph, depthX, depthY, pixelWidth, allUsersDepthData, 0, 255, 0, 255);		
			}	
			
			
			return new Vector3(depthX,depthY,depthZ   );
		}
		


		public void DrawPointOnDepthMap(int w, int h, int depthX, int depthY, int pixelWidth, byte[]  _allUsersDepthData, byte r, byte g ,byte b,byte a  )
		{
			if (isSpotInsideDepthMap (depthX, depthY)) {
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray (w, h, depthX, depthY, pixelWidth, _allUsersDepthData, r, g, b, a);		
			}
		}


		float GetHeight (ref Dictionary<int, ImiPlayerInfo> playerInfos, int controlId, bool isDrawOnDepthMap )
		{
			int headDepthX = 0;
			int headDepthY = 0;
			int depthZ = 0;

			int w = DEPTHWIDTH;
			int h = DEPTHHEIGHT;



			ImiWrapper.ImiVector4 jointPosV4 =
				playerInfos [controlId].
					skeletons[(int)ImiSkeleton.Index.HEAD].positionV4;

			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				jointPosV4,
				ref headDepthX,
				ref headDepthY,
				ref depthZ,
				ImiResolution.Type._640x480);


			//Get the pixel pos of head and head top.
			int pixDist_HeadTop_And_HeadOrig = IMIBodyMeaTool.GetHead2TopPixDist (depthPlayerDataOriginal, w, h,headDepthX, headDepthY, boundThreshval);
			int topY = headDepthY - pixDist_HeadTop_And_HeadOrig;


			float bodyHeight = 0f;
			//Draw head spots and the head top spot.
			if (isSpotInsideDepthMap (headDepthX, headDepthY)) {
				headOrigPixPos = headDepthY;
				headTopPixPosY = topY;
				headOrigDepth = depthPlayerDataOriginal [headDepthY * w + headDepthX] >> 3;
				headTopDepth = depthPlayerDataOriginal [topY * w + headDepthX] >> 3; 
				//headTopDepth = headOrigDepth+110;// depthPlayerDataOriginal [topY * w + headDepthX] >> 3; 
				
				if(isDrawOnDepthMap)
				{
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray (w, h, headDepthX, headDepthY, 3, allUsersDepthData, 0, 255, 0, 255);

				//getSomeDepthValue(depthPlayerDataOriginal, w,headDepthX,headDepthY,boundThreshval);
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray(w,h,headDepthX,topY,5,allUsersDepthData,255,255,255,255);	
				}

				//calculate the player height  according to the pixel pos of headTop and VerticalPlanePixPosY and headTopDepth.
				int dw = DEPTHWIDTH;
				int dh = DEPTHHEIGHT;

				bodyHeight = IMIBodyMeaTool.GetHeightByHeadTopPixPos (dh, dw, tiltDownAngle, 48, headTopPixPosY, headTopDepth, setDeviceHeight,heightOffsetY);

			}	

			return bodyHeight;
		}


		public Vector2 GetHeadTopPixPos(ref Dictionary<int, ImiPlayerInfo> playerInfos , int controlId, bool isDrawOnDepthMap )
		{
			int headDepthX = 0;
			int headDepthY = 0;
			int depthZ = 0;
			
			int w = DEPTHWIDTH;
			int h = DEPTHHEIGHT;
			
			
			
			ImiWrapper.ImiVector4 jointPosV4 =
				playerInfos [controlId].
					skeletons[(int)ImiSkeleton.Index.HEAD].positionV4;
			
			ImiWrapper.ConvertSkeletonPointToDepthPoint (
				jointPosV4,
				ref headDepthX,
				ref headDepthY,
				ref depthZ,
				ImiResolution.Type._640x480);
			
			
			//Get the pixel pos of head and head top.
			int pixDist_HeadTop_And_HeadOrig = IMIBodyMeaTool.GetHead2TopPixDist (depthPlayerDataOriginal, w,h, headDepthX, headDepthY, boundThreshval);
			int topY = headDepthY - pixDist_HeadTop_And_HeadOrig;
			
			if(  isDrawOnDepthMap )
			{
				DrawingSpotsOnTexture.DrawPixelsSquareOnByteArray(w,h,headDepthX,topY,5,allUsersDepthData,255,255,255,255);	
			}
			
			
			return new Vector2(headDepthX, topY);
			
		}





		bool isSpotInsideDepthMap (int depthX, int depthY)
		{
			if ((depthX >= 0)
				&& (depthX < DEPTHWIDTH)
				&& (depthY >= 0)
				&& (depthY < DEPTHHEIGHT)) {
				return true;		
			}	

			return false;
		}


		void DrawHorilineOnUserDepthColor (byte[]  _usersDepthColors, int depthW, int depthH, int pixposXMin, int pixposXMax, int pixposY, byte r, byte g, byte b, byte a)
		{
			for (int i=pixposXMin; i<pixposXMax; i++) {
				_usersDepthColors [(pixposY * depthW + i) * 4] = (byte)(r);
				_usersDepthColors [(pixposY * depthW + i) * 4 + 1] = (byte)(g);
				_usersDepthColors [(pixposY * depthW + i) * 4 + 2] = (byte)(b);
				_usersDepthColors [(pixposY * depthW + i) * 4 + 3] = (byte)a;
			}
		}

		float GetThicknessBy2PixPoses (Vector2 pixPos0, Vector2 pixPos1, int depthVal)
		{
			Vector3 WorldPosEnd0 = GetWorldPos_by_DepthPixCoord2 ((int)(pixPos0.x), (int)(pixPos0.y), depthVal);
			Vector3 WorldPosEnd1 = GetWorldPos_by_DepthPixCoord2 ((int)(pixPos1.x), (int)(pixPos1.y), depthVal);
			return Mathf.Abs (WorldPosEnd0.x - WorldPosEnd1.x);
		}

		//
		public static Vector3 GetWorldPos_by_DepthPixCoord2 (int PixPosX, int PixPosY, int depthval)
		{
			ImiWrapper.ImiVector4 _jointPosV4 = new ImiWrapper.ImiVector4 ();
			ImiWrapper.ConvertDepthPointToSkeletonPoint (
				PixPosX,
				PixPosY,
				depthval,
				ref _jointPosV4,
				ImiResolution.Type._640x480);
			return  new Vector3 (_jointPosV4.x, _jointPosV4.y, _jointPosV4.z);
		}


		public Vector3 GetJointSpacePos(ref Dictionary<int, ImiPlayerInfo> playerInfos,  int userID,  ImiSkeleton.Index jointIDX)
		{
			ImiWrapper.ImiVector4 jointPosV4 =
				playerInfos [userID].
					skeletons[(int)jointIDX].positionV4;
			
		     
			return new Vector3( jointPosV4.x,jointPosV4.y,jointPosV4.z );
		}




		float GetThicknessFromOnePixPos (ushort[] _depthPlayerDataOriginal, 
		                                 int depthW, 
		                                 int depthH, 
		                                 int pixPosX,
		                                 int pixPosY,
		                                 ushort boundThreshval,
		                                 int depthVal,
		                                 bool isDrawOrNot)
		{
			//ushort threshval = 500; //mm 0.5m, the threshold diff value of two neighbout pixels by which we can tell if we reach the boundary of a contour or not    from a depth map.       
			
			Vector2 minEnd =  IMIBodyMeaTool.GetContourMinEnd(depthW, 
			                                                  depthH, 
			                                                  pixPosX,
			                                                  pixPosY,
			                                                  _depthPlayerDataOriginal,
			                                                  boundThreshval);
			Vector2 maxEnd =  IMIBodyMeaTool.GetContourMaxEnd (depthW, 
			                                                   depthH, 
			                                                   pixPosX,
			                                                   pixPosY,
			                                                   _depthPlayerDataOriginal,
			                                                   boundThreshval);			
			
			if (isDrawOrNot) {
				DrawHorilineOnUserDepthColor (allUsersDepthData,
				                              depthW, depthH, 
				                              (int)minEnd.x, (int)maxEnd.x, (int)maxEnd.y, 255, 255, 0, 255);
			}		
			
			return  GetThicknessBy2PixPoses(minEnd, maxEnd, depthVal);
		}

			

		float GetThickestPartBy2PixPoses( int depthW, int depthH,  ushort[] _depthPlayerDataOriginal,  ushort threshboundaryValue,
		                                 Vector2 jointPixPos0,Vector2 jointPixPos1,
		                                  bool isDrawOrNot)
		{    
			//ushort threshval = 500; //mm 0.5m, the threshold diff value of two neighbout pixels by which we can tell if we reach the boundary of a contour or not    from a depth map.       
			//Draw the left half of line
			
			Vector2 minEnd =Vector2.zero;
			Vector2  maxEnd =Vector2.zero;



			IMIBodyMeaTool.GetThickestPixPosesByDepth(depthW, depthH,  jointPixPos0,jointPixPos1,ref minEnd,ref maxEnd,_depthPlayerDataOriginal,threshboundaryValue);

			Vector2 waistSideMidPixPos=(minEnd + maxEnd)/2;
			int waistSideMidPixPosX=(int)(waistSideMidPixPos.x);
			int waistSideMidPixPosY=(int)(waistSideMidPixPos.y);

			if(isDrawOrNot)
			{
				DrawPointOnDepthMap(depthW,depthH,(int)jointPixPos0.x, (int)jointPixPos0.y, 
				                    7,allUsersDepthData,200,120,255,255);

				DrawPointOnDepthMap(depthW,depthH,(int)jointPixPos1.x, (int)jointPixPos1.y, 
				                    7,allUsersDepthData,200,120,255,255);

				DrawPointOnDepthMap(depthW,depthH,waistSideMidPixPosX, waistSideMidPixPosY, 
				                    7,allUsersDepthData,255,255,0,255);

				DrawPointOnDepthMap(depthW,depthH,(int)minEnd.x, (int)minEnd.y, 
				                    7,allUsersDepthData,255,255,255,255);

				DrawPointOnDepthMap(depthW,depthH,(int)maxEnd.x, (int)maxEnd.y, 
				                    7,allUsersDepthData,255,255,255,255);

				//DrawHorilineOnUserDepthColor(allUsersDepthData,depthW,depthH,(int)minEnd.x,
				                            // (int)maxEnd.x,waistSideMidPixPosY,240,100,50,255);
			}

			int	hipsSideDepth =((depthPlayerDataOriginal [waistSideMidPixPosY * depthW+ waistSideMidPixPosX]) >> 3)
				                       +adjustDeepingLengthForSideHips ;
		
			  return GetThicknessBy2PixPoses(minEnd, maxEnd, hipsSideDepth);
		}




		float GetThicknessFromPixPosesArr( int depthW, int depthH,  ushort[] _depthPlayerDataOriginal,  ushort threshboundaryValue,
		                                  Vector2 jointPixPos0,Vector2 jointPixPos1,int adjustDeepingLength,
		                                 bool isDrawOrNot)
		{    
			//ushort threshval = 500; //mm 0.5m, the threshold diff value of two neighbout pixels by which we can tell if we reach the boundary of a contour or not    from a depth map.       
			//Draw the left half of line
			ArrayList PixPosesArr=new ArrayList();
			PixPosesArr.Clear();		
			
			
			IMIBodyMeaTool.GetArrOfPixPosesOfThicknessEndsInHeightRange(depthW, depthH,  
			                                                            jointPixPos0,jointPixPos1,ref PixPosesArr,_depthPlayerDataOriginal,threshboundaryValue);
			
			if(PixPosesArr.Count<=0)
			{
				Debug.LogWarning("Array empty Problem in detecting side waist ");
			}
			
			if(isDrawOrNot)
			{
				foreach(Vector3 posEnds in PixPosesArr)
				{
					DrawPointOnDepthMap(depthW,depthH,(int)posEnds.x, (int)posEnds.z, 
					                    7,allUsersDepthData,255,255,0,255);
					DrawPointOnDepthMap(depthW,depthH,(int)posEnds.y, (int)posEnds.z, 
					                    7,allUsersDepthData,255,255,0,255);
				}
			}



			int MaxPixPosWidth=0;
			//Get the max Waist pix pos width of the range of waist height.
			//This can be used as if one row of waist pixpels is good enough.
			foreach(Vector3 posEnds in PixPosesArr)
			{
				int minend=(int)posEnds.x;
				int maxend=(int)posEnds.y;
				int pixposy=(int)posEnds.z;
				int waistPixPosRowWidth = maxend-minend;
				if(waistPixPosRowWidth>MaxPixPosWidth)
				{
					MaxPixPosWidth=waistPixPosRowWidth;
				}
			}

			if(MaxPixPosWidth<8)
			{
				Debug.LogError("Warning , the max waist pix pos width is smaller than 8 pixes.  This is abnormal");
			}



			ArrayList ThicknessArr=new ArrayList();
			foreach(Vector3 posEnds in PixPosesArr)
			{
				int minend=(int)posEnds.x;
				int maxend=(int)posEnds.y;
				int pixposy=(int)posEnds.z;

				int currRowPixPosWidth=Mathf.Abs(maxend-minend);


				//Get the background pix count in the current pix row. 
				//If there are too many bk pix(hollow ) in the current row, we set this row unqualified to  fit the waist.
				int bkPixCount=0;
				for(int i=minend;i<maxend;i++)
				{
					int localPlayerId =((depthPlayerDataOriginal [pixposy * depthW+ i]) & 7);
					if(localPlayerId<=0)
					{
				    		bkPixCount++;
					}
				}

				if(
					((((float)currRowPixPosWidth)/((float)MaxPixPosWidth))>0.55f)
					                      &&(
					                             (((float)bkPixCount )/((float)(currRowPixPosWidth)))<0.4f
				                            )
					)

				{
					if(((depthPlayerDataOriginal [pixposy * depthW+ (minend+maxend)/2]) & 7)>0)
					{

						int	hipsSideDepth =((depthPlayerDataOriginal [pixposy * depthW+ (minend+maxend)/2]) >> 3)
											+adjustDeepingLength;
						float waistthicknessTmp= GetThicknessBy2PixPoses(new Vector2(minend,  pixposy), 
						                                                 new Vector2(maxend,  pixposy), hipsSideDepth);

					    	ThicknessArr.Add(waistthicknessTmp);
					}
				}

			}


//			int	hipsSideDepth =((depthPlayerDataOriginal [waistSideMidPixPosY * depthW+ waistSideMidPixPosX]) >> 3)
//				+adjustDeepingLengthForSideHips ;
			
			//return GetThicknessBy2PixPoses(minEnd, maxEnd, hipsSideDepth);
			return GetMiddleAgeValue(ThicknessArr);
		}
//

















		//By this value, we will determine  if the player is side facing or frontal facing the device
		public  float GetheadShoulderDeltaZXRatio(Dictionary<int, ImiPlayerInfo> tplayerInfos,int userID)
		{
			ImiWrapper.ImiVector4 shouldercenterPos= tplayerInfos [userID].skeletons[(int)ImiSkeleton.Index.SHOULDER_CENTER].positionV4;
			ImiWrapper.ImiVector4 lshoulderpos= tplayerInfos [userID].skeletons[(int)ImiSkeleton.Index.SHOULDER_LEFT].positionV4;
			ImiWrapper.ImiVector4 rshoulderpos= tplayerInfos [userID].skeletons[(int)ImiSkeleton.Index.SHOULDER_RIGHT].positionV4;

			ImiWrapper.ImiVector4 closeShoulderPos=new ImiWrapper.ImiVector4();
			if(Mathf.Abs(lshoulderpos.z)< Mathf.Abs(rshoulderpos.z))
			{
				closeShoulderPos=lshoulderpos;
			}
			else
			{
				closeShoulderPos=rshoulderpos;				
			}

			float ShoulderHeadDeltaX=( closeShoulderPos.x- shouldercenterPos.x);
			float ShoulderHeadDeltaZ=Mathf.Abs(shouldercenterPos.z-closeShoulderPos.z);

			if(ShoulderHeadDeltaX==0.0f)
			{
				return 100f;
			}
			else
			{
				XZDeltaSmth.InsertValue(ShoulderHeadDeltaZ/ShoulderHeadDeltaX);
				return XZDeltaSmth.GetFilteredValue();

				//return (ShoulderHeadDeltaZ/ShoulderHeadDeltaX);
			}
		}


	    public float GetMiddleAgeValue(ArrayList valueArr)
		{
			if(valueArr.Count<=0)
			{
				Debug.LogWarning("valueArr is empty");
				return 0f;
			}

			if(valueArr.Count<=10)
			{
				Debug.LogWarning("valueArr is less than 10. Too few for estimation");
				return GetAvg(0, valueArr.Count, valueArr);
			}		


			valueArr.Sort();
//			foreach(float val in  valueArr )
//			{
//				Debug.Log("-----------sorvalue: "+ val.ToString());
//			}

			int bgidx=valueArr.Count/3;
			int enidx=valueArr.Count-bgidx;


			return GetAvg(bgidx, enidx, valueArr);
		}


		float GetAvg(int beginIdx, int endIdx, ArrayList valArr   )
		{
			float sum=0f;
			for(int i=beginIdx;i<endIdx;i++)
			{
				sum+=(float)(valArr[i]);
			}

			return sum/((float)(endIdx- beginIdx));
		}



		public void ConcludeHeight()
		{
			playerHeight=GetMiddleAgeValue(  heightSmoothArr);

			if (playerHeight <= 0) {
				Debug.LogWarning ("playerHeight length not correct : "+playerHeight.ToString()+"   " + "playerHeightArr length: "+ heightSmoothArr.Count.ToString() );
			}
		}

		public void ConcludeShoulderWidth()
		{
			ShoulderWidth=GetMiddleAgeValue(  ShoulderWidthArr)*1.1f;
			if (ShoulderWidth <= 0) {
				Debug.LogWarning ("ShoulderWidth length not correct : "+ShoulderWidth.ToString()+"   " + 
					"ShoulderWidthArr length: "+ ShoulderWidthArr.Count.ToString() );
			}

		}

		public void ConcludeArmLength()
		{
			ArmLength=GetMiddleAgeValue(  ArmLengthArr)*1.4f;
			if (ArmLength <= 0) {
				Debug.LogWarning ("Arm length not correct : "+ArmLength.ToString()+"   " + "ArmLengthArr length: "+ ArmLengthArr.Count.ToString() );
			}
		}

		public void ConcludeLegLength()
		{
		   LegLength=  GetMiddleAgeValue(  LegLengthArr)*0.97f; 
			if (LegLength <= 0) {
				Debug.LogWarning ("LegLength length not correct : "+LegLength.ToString()+"   " + 
					"LegLengthARR length: "+ LegLengthArr.Count.ToString() );
			}
		}

		public void ConcludeChestFront()
		{
//			chestWidth=GetMiddleAgeValue(  chestSmthWidthArr); 
//			if (chestWidth <= 0) {
//				Debug.LogWarning ("chestWidth length not correct : "+chestWidth.ToString()+"   " + 
//					"chestWidthArr length: "+ chestSmthWidthArr.Count.ToString() );
//			}


			//Since 2017 0623  Draw front final result.
			chestFrontDepthLineMgr.GetFinalDepthData ();
//			chestFrontDepthLineMgr.DrawFinalDataDepthVal ();
//			chestFrontDepthLineMgr.DrawGraph ();
		}






		public void ConcludeChestThick()
		{
		   chestThickness=  GetMiddleAgeValue(  chestSmthThicknessArr); 	
			if (chestThickness <= 0) {
				Debug.LogWarning ("chestThickness length not correct : "+chestThickness.ToString()+"   " + 
					"chestThicknessARR length: "+ chestSmthThicknessArr.Count.ToString() );
			}

		}

		public void ConcludeWaistFront()
		{
//		   waistWideness=  GetMiddleAgeValue(  waistSmthWidthArr); 
//			if (waistWideness <= 0) {
//				Debug.LogWarning ("waistWideness length not correct : "+waistWideness.ToString()+"   " + 
//					"waistSmthWidthArr length: "+ waistSmthWidthArr.Count.ToString() );
//			}

			waistFrontDepthLineMgr.GetFinalDepthData ();
		//	waistDataSamplingValueStr = waistFrontDepthLineMgr.GetFinalBodySampleDataString ();
			
//			waistFrontDepthLineMgr.DrawFinalDataDepthVal ();
//			waistFrontDepthLineMgr.DrawGraph ();

		}
		
		public void ConcludeWaistThick()
		{
		   waistThickness=  GetMiddleAgeValue(  waistSmthThickArr); 
			if (waistThickness <= 0) {
				Debug.LogWarning ("waistThickness length not correct : "+waistThickness.ToString()+"   " + 
					"waistThicknessArr length: "+ waistSmthThickArr.Count.ToString() );
			}
		}

		public void ConcludeHipsFront()
		{
//		   hipsWidth=  GetMiddleAgeValue(  hipsSmthWidthArr); 
//			if (hipsWidth <= 0) {
//				Debug.LogWarning ("hipsWidth length not correct : "+hipsWidth.ToString()+"   " + 
//					"hipsSmthWidthArr length: "+ hipsSmthWidthArr.Count.ToString() );
//			}

			
			hipsFrontDepthLineMgr.GetFinalDepthData ();
//			hipsFrontDepthLineMgr.DrawFinalDataDepthVal ();
//			hipsFrontDepthLineMgr.DrawGraph ();


		}
		
		public void ConcludeHipsThick()
		{
		   hipsThickness=  GetMiddleAgeValue(  hipsSmthThicknessArr); 

			if (hipsThickness <= 0) {
				Debug.LogWarning ("hipsThickness length not correct : "+hipsThickness.ToString()+"   " + 
					"hipsSmthThicknessArr length: "+ hipsSmthThicknessArr.Count.ToString() );
			}
		}


		public bool isChestFrontNormal()
		{
			if (chestFrontDepthLineMgr.frontLen0 <= 0f) {
				return false;
			}
			return true;
		}

		public bool isChestThickNormal()
		{
			if (chestThickness <= 0f) {
				return false;
			}
			return true;
		}

		public bool isWaistFrontNormal()
		{
			if (waistFrontDepthLineMgr.frontLen0 <= 0f) {
				return false;
			}
			return true;
		}

		public bool isWaistThicknessNormal()
		{
			if (waistThickness <= 0f) {
				return false;
			}
			return true;
		}


		public bool isHipsFrontNormal()
		{
			if (hipsFrontDepthLineMgr.frontLen0 <= 0f) {
				return false;
			}
			return true;
		}


		public bool isHipsThicknessNormal()
		{
			if (hipsThickness <= 0f) {
				return false;
			}
			return true;
		}


		public bool isHeightNormal()
		{
			if (playerHeight <= 0f) {
				return false;
			}
			return true;
		}

		public bool isShoulderWidthNormal()
		{
			if (ShoulderWidth <= 0f) {
				return false;
			}
			return true;
		}

		public bool isArmlengthNormal()
		{
			if (ArmLength <= 0f) {
				return false;
			}
			return true;
		}

		public bool isLeglengthNormal()
		{
			if (LegLength <= 0f) {
				return false;
			}
			return true;
		}



		int RangeValue(int value, int min, int max)
		{
			if(value<min)value=min;
			if(value>=max)value=max-1;
			
			return value;
		}


		void OnGUI ()
		{
			//		GUILayout.Label("origHeadDepth:   "+depthheadOrig.ToString());
			//		GUILayout.Label("HeadDepth1:   "+depthhead1.ToString());
			//		GUILayout.Label("HeadDepth2:   "+depthhead2.ToString());
			//		GUILayout.Label("HeadDepth3:   "+depthhead3.ToString());
			//		GUILayout.Label("HeadDepth4:   "+depthhead4.ToString());
			//		GUILayout.Label("HeadDepth5:   "+depthhead5.ToString());

			//		GUILayout.Label("HeadOrigPixPos:   "+headOrigPixPos.ToString());
			//		GUILayout.Label("headTopPixPosY:   "+headTopPixPosY.ToString());
			//		GUILayout.Label("HeadOrigDepth:   "+headOrigDepth.ToString());


//			switch(mbodymeaState)
//			{
//			case BODYMEASTATE.IDLE0:
//				GUILayout.Label ("IN Idle State 0");
//				break;
//			case BODYMEASTATE.FRONT:
//				GUILayout.Label ("During Measurement State");		
//				GUILayout.Label ("Player Height In Measure :   " + playerHeight.ToString ());		
//				GUILayout.Label ("Player Waist Width :   " + waistWideness.ToString ());
//				break;
//			case BODYMEASTATE.IDLE1:
//				GUILayout.Label ("Player Height :   " + playerHeight.ToString ());	
//				break;
//			default:
//				break;
//			}
//
//

			//		if(PlayHeightDic.Count>0)
			//		{
			//			foreach (KeyValuePair<uint, float> pair in PlayHeightDic)
			//			{
			//				GUILayout.Label( pair.Key.ToString()+"   PlayerHeight:   "+pair.Value.ToString());
			//			}
			//		}
		}





		//code for getting depth values of some points beside the point of head
		//	int depthheadOrig=0;
		//	int depthhead1=0;
		//	int depthhead2=0;
		//	int depthhead3=0;
		//	int depthhead4=0;
		//	int depthhead5=0;
		//
		//
		//
		//	private void getSomeDepthValue (ushort[] depthPlayerDataOriginal, int depthW, int OrigHeaddepthMapPixX, int OrigHeaddepthMapPixY, int boundThreshval)
		//	{
		//		// if the depth val of high point is larger than the head point by this value,  we  regard that point as a backpoint.  
		//		//ushort threshval = 60; //mm
		//		int dist = 0;
		//		int headX = OrigHeaddepthMapPixX;
		//		int headY = OrigHeaddepthMapPixY;
		//		int headOrigIdx = headY * depthW + headX;
		//		//the idx which is higher than the head;
		//		int headHighIdx = headOrigIdx;
		//		//Compare the point higher than the certain point/head point, one pix by one pix. Until we found the one on the border of the contour.
		//
		//		depthheadOrig=depthPlayerDataOriginal [headHighIdx]>>3;
		//		depthhead1=depthPlayerDataOriginal [headHighIdx-depthW]>>3;
		//		depthhead2=depthPlayerDataOriginal [headHighIdx-depthW*2]>>3;
		//		depthhead3=depthPlayerDataOriginal [headHighIdx-depthW*3]>>3;
		//		depthhead4=depthPlayerDataOriginal [headHighIdx-depthW*4]>>3;
		//		depthhead5=depthPlayerDataOriginal [headHighIdx-depthW*5]>>3;
		//	}


	}
}
